home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / ctrlc.exe / CTRLC.C < prev    next >
C/C++ Source or Header  |  1992-09-30  |  8KB  |  234 lines

  1. // ===========================================================
  2. // ctrlc.c - Ctrl-C, Ctrl-Break handlers. AT-BIOS int 15h hook
  3. // ===========================================================
  4. //
  5. //    Modification History
  6. //    ====================
  7. //    -Sym-    -Date-    Who    -Comments-
  8. //    =====    ======    ===    ==========
  9. //    none    093092    rp    Modified to be standalone for upload to CI$.
  10. //                        Extracted some typedefs, etc. from header file(s).
  11. //                        Translated debug stuff, etc to more std syntax.
  12. //
  13. #include <dos.h>
  14.  
  15. // ============================================================================
  16. //    Note:    All routines originally in file KBD.ASM, via TASM's ideal mode.
  17. //            File translated to straight 'C' under Turbo C++ v1.0, as part of
  18. //            eliminating all *.asm files from project. This file was then
  19. //            updated to C++ and to conform w/ Borland C++ v3.10
  20. //            ( different getvect() & setvect() typecasts, etc ). Net result,
  21. //            all files in project now compile successfully in C++ mode.
  22. //
  23. //            !! YOU WILL GET SYNTAX ERRORS IF YOU TRY TO COMPILE IN 'C' MODE !!
  24. //            These are mainly due to the use of 'Boolean' instead of
  25. //            'enum Boolean'. There may be others.
  26. //
  27. //    Note:    This module assumes that all keyboard input is handled
  28. //            (in another file) via BIOS int 16h functions. Thus the int 23h
  29. //            intercept should never actually be seen. It HAS NOT been tested
  30. //            with 'stdin' or 'cin' ! Note that int 23h may also called by abort
  31. //            processing (e.g. via 'Abort, Retry, Ignore').
  32. //
  33. //    Note:    This file assumes routines are being run on an AT-class machine.
  34. //            For an XT-class, the int 15h hook is NOT valid !
  35. //
  36. //    Note:    Repeated blowups have shown that variables declared inside of
  37. //            interrupt handlers should be static ! This minimizes stack usage,
  38. //            and prevents _chain_intr() from getting too confused.
  39. // ============================================================================
  40.  
  41. ////////////////////////////////////
  42. // typedefs from header file <std.h>
  43. ////////////////////////////////////
  44. enum Boolean { False, True };
  45. typedef unsigned char  uchar;
  46. typedef unsigned short ushort;
  47. typedef unsigned long  ulong;
  48.  
  49. //////////////////////////////
  50. // Global Functions, variables
  51. //////////////////////////////
  52. void init_keyboard();            // module initialization (hook int's)
  53. void term_keyboard();            // module termination (restore int's)
  54. Boolean breakflag = False;        // set to True on Ctrl-Break, Ctrl-C
  55. Boolean sysRequest = False;        // toggled on SysRq key.
  56.                                 //  used for debug enable/disable
  57.  
  58. //////////////////
  59. // Local variables
  60. //////////////////
  61. static Boolean installed = False;    // Installation flag
  62. static Boolean trap_dosbrk = True;    // False will disable int 23h intercept
  63. static Boolean trap_biosbrk = True;    // False will disable int 1Bh intercept
  64. static uchar old_dosbrk;            // Saved dos break state. 'Break' will
  65.                                     //  be disabled if trap_dosbrk == True
  66.                                     //  and restored at program exit
  67.  
  68. static void _interrupt (_far *old15h)(...) = 0;    // saved interrupt vectors
  69. static void _interrupt (_far *old1Bh)(...) = 0;
  70. static void _interrupt (_far *old23h)(...) = 0;
  71.  
  72.  
  73. ///////////////////////////////////////////////////////////////////////////////
  74. // The BIOS Ctrl-Break trap is easiest.
  75. //    Just set the global breakflag & exit
  76. ///////////////////////////////////////////////////////////////////////////////
  77. static void _interrupt new1Bh(...)
  78.     {
  79.     breakflag = True;
  80.     }
  81.  
  82. /////////////////////////////////////////////////
  83. // The 80x86 family cpu's carry flag bit position
  84. /////////////////////////////////////////////////
  85. const unsigned CPU_CARRY = 0x0001;
  86.  
  87. ///////////////////////////////////////////////////////////////////////////////
  88. // DOS Ctrl-C is a little more difficult.
  89. //    First, set the global breakflag.
  90. //    Then clear the cpu's carry flag to tell dos to ignore the 'error' of
  91. //  a Ctrl-C character.
  92. //
  93. // Only argument we care about happens to be the farthest away on the stack !
  94. ///////////////////////////////////////////////////////////////////////////////
  95. #pragma argsused
  96. static void _interrupt _far new23h( unsigned bp, unsigned di, unsigned si,
  97.     unsigned ds, unsigned es, unsigned dx, unsigned cx, unsigned bx,
  98.     unsigned ax, unsigned ip, unsigned cs, unsigned flags, ... )
  99.     {
  100.     breakflag = True;
  101.     flags &= ~CPU_CARRY;
  102.     }
  103.  
  104. //
  105. // trap keyboard scan codes on AT-class only
  106. //
  107. static Boolean trap_15h = True;        // Needed if trap_sysreq or trap_scan
  108. static Boolean trap_sysreq = True;    // Trap the SysRq key
  109. static Boolean trap_scan = False;    // Trap any scan code other than sysreq
  110. static Boolean trap_prtsc = False;    // Trap PrtSc key
  111. static Boolean trap_reboot = False;    // Trap Ctrl-Alt-Del
  112.  
  113. #define BIOS_DATA    0x40        // bios data segment
  114.  
  115. const ushort SHIFT_FLAGS = 0x17;        // shift key flags byte
  116. const uchar  ALT_SHIFT   = 0x08;        // alt shift bit flag
  117. const uchar  CTRL_SHIFT  = 0x04;        // ctrl shift bit flag
  118.  
  119. const uchar  CTRL_ALT     = ALT_SHIFT | CTRL_SHIFT;
  120.  
  121. #define FN_SYSREQ    0x85        // int 15h reg ah if sysreq hit, release
  122. #define FN_SCAN        0x4F        // int 15h reg ah on key hit, release
  123.  
  124. #define M_DEL        0x53        // delete key make
  125. #define M_PRTSC        0x37        // prtsc key make
  126.  
  127. //
  128. // Maybe intercept the keyboard raw-scan codes, and SysReq keys.
  129. //
  130. #pragma argsused
  131. static void _interrupt _far new15h( unsigned bp, unsigned di, unsigned si,
  132.     unsigned ds, unsigned es, unsigned dx, unsigned cx, unsigned bx,
  133.     unsigned ax, unsigned ip, unsigned cs, unsigned flags, ...)
  134.     {
  135.     static uchar _far *shiftFlags =
  136.             (uchar _far *)MK_FP( BIOS_DATA, SHIFT_FLAGS );
  137.     static Boolean chain15h;    // Should we chain to old handler ?
  138.     static uchar regAH;            // For clarity
  139.     static uchar regAL;
  140.  
  141.     chain15h = True;            // Set at each entry !
  142.     regAL = (uchar) ax;            // extract for clarity
  143.     regAH = (uchar)(ax >> 8);
  144.  
  145.     ///////////////////
  146.     // Maybe trap SysRq
  147.     ///////////////////
  148.     if ( regAH == FN_SYSREQ && trap_sysreq )
  149.         {
  150.         chain15h = False;
  151.         if ( regAL )
  152.             sysRequest = (sysRequest) ? False: True;
  153.         }
  154.     ////////////////////////
  155.     // Maybe trap scan codes
  156.     ////////////////////////
  157.     else if ( regAH == FN_SCAN && trap_scan )
  158.         {
  159.         switch ( regAL )
  160.             {
  161.             case M_DEL:
  162.                 if ( trap_reboot && (*shiftFlags & CTRL_ALT) == CTRL_ALT )
  163.                     {
  164.                     flags &= ~CPU_CARRY;    // discard scan code
  165.                     chain15h = False;        // don't chain
  166.                     }
  167.                 break;
  168.  
  169.             case M_PRTSC:
  170.                 if ( trap_prtsc )
  171.                     {
  172.                     flags &= ~CPU_CARRY;    // discard scan code
  173.                     chain15h = False;        // don't chain
  174.                     }
  175.                 break;
  176.  
  177.             default:
  178.                 break;                        // all others pass thru
  179.             }
  180.     }
  181.     if ( chain15h )
  182.         _chain_intr( old15h );
  183.     }
  184.  
  185. /////////////////////////////////
  186. //    term_keyboard() - unhook ints
  187. /////////////////////////////////
  188. void term_keyboard()
  189.     {
  190.     if ( !installed )
  191.         return;
  192.     if ( trap_15h )
  193.         setvect( 0x15, old15h );
  194.     if ( trap_biosbrk)
  195.         setvect( 0x1B, old1Bh );
  196.     if ( trap_dosbrk )
  197.         {
  198.         _AX = 0x3301;                // set break state
  199.         _DL = old_dosbrk;            // to original
  200.         geninterrupt( 0x21 );
  201.         setvect( 0x23, old23h );
  202.         }
  203.     installed = False;
  204.     }
  205.  
  206. /////////////////////////////////////////
  207. //    init_kybd() - keyboard initialization
  208. /////////////////////////////////////////
  209. void init_keyboard()
  210.     {
  211.     if ( installed )
  212.         return;
  213.     if ( trap_15h )
  214.         {
  215.         old15h = getvect( 0x15 );
  216.         setvect( 0x15, (void _interrupt (_far*)(...)) new15h );
  217.         }
  218.     if ( trap_biosbrk )
  219.         {
  220.         old1Bh = getvect( 0x1B );
  221.         setvect( 0x1B, new1Bh );
  222.         }
  223.     if ( trap_dosbrk )
  224.         {
  225.         _AX = 0x3302;                // exchange break state
  226.         _DL = 0;                    // to off
  227.         geninterrupt( 0x21 );
  228.         old_dosbrk = _DL;            // save original
  229.         old23h = getvect( 0x23 );
  230.         setvect( 0x23, (void _interrupt (_far*)(...)) new23h );
  231.         }
  232.     installed = True;
  233.     }
  234.